/*
 * ArchivoUtils.cpp
 *
 *  Created on: 19/05/2013
 *      Author: jonathan
 */

#include "ArchivoUtils.h"
#include <iostream>
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <list>
#include <cstdio>
#include "excepciones/EliminarArchivoException.h"
using namespace std;

PunteroPosiciones leerNumeroVariableLargo(BitStream* stream, EnteroLargo longitud) {
	EnteroLargo numero = 0;
	bool sigue = true;
	while (sigue) {
		sigue = stream->getBit();
		//		numero = stream->getBit();
		for (EnteroLargo i = 0; i < longitud; i++) {
			numero <<= 1;
			if (stream->getBit()) {
				numero += 1;
			}
		}
	}
	return numero;
}
EnteroLargo leerNumeroVariable(BitStream* stream, EnteroLargo longitud) {
	EnteroLargo numero = 0;
	bool sigue = true;
	while (sigue) {
		sigue = stream->getBit();
		//		numero = stream->getBit();
		for (EnteroLargo i = 0; i < longitud; i++) {
			numero <<= 1;
			if (stream->getBit()) {
				numero += 1;
			}
		}
	}
	return numero;
}

void removeFile(const FileName& fileName) {
	if (remove(fileName) != 0)
		throw EliminarArchivoException(fileName);
}

void escribirNumeroVariable(BitStream* stream, EnteroLargo numero,
		EnteroLargo longitudBloque) {
	//Cuantos bits tiene el tipo.
	EnteroLargo bits = sizeof(EnteroLargo) * 8;
	EnteroLargo bit = 1;
	EnteroLargo mascara = bit << (bits - 1);
	int contador = 0;
	// cuento cuantos bits tiene la variable a escribir
	bool salir = false;
	while (mascara > 0 && salir == false) {
		contador++;
		salir = mascara & numero;
		mascara >>= 1;
	}
	int cantidadBitsAEscribir = bits + 1 - contador;
	//cantidad de bloques a escribir
	int cantBloquesEscribir = cantidadBitsAEscribir / longitudBloque;
	if (cantidadBitsAEscribir % longitudBloque > 0) {
		cantBloquesEscribir++;
	}
	//ahora empiezo a escribir;
	mascara = 1 << (cantBloquesEscribir * longitudBloque);
	//	string salida;
	//por cantidad de bytes.
	for (int i = 0; i < cantBloquesEscribir; i++) {
		//si hay mas bloques escribo un sigue.
		stream->putBit((cantBloquesEscribir > i + 1) ? true : false);
		//		salida += "|";
		//		salida += ((cantBloquesEscribir > i+1) ? "1" : "0");
		//escribo por bloques.
		for (EnteroLargo j = 0; j < longitudBloque; j++) {
			mascara >>= 1;
			stream->putBit((mascara & numero) ? true : false);
			//			salida += ((mascara & numero) ? "1" : "0");
		}
	}
	//		cout<< salida<< endl;
}

PunteroPosiciones leerBinario(BitStream* bs, int cantBits) {
	PunteroPosiciones ent= 0;
	for(int i=cantBits; i>0; i--){
		ent<<=1;
		if(bs->getBit()){
			ent +=1;
		}
	}
	return ent;
}

void escribirBinario(BitStream* bs, PunteroPosiciones nro, int bits) {
	PunteroPosiciones uno = 1;
	PunteroPosiciones mascara = uno << (bits-1);
	for (int j = 0; j < bits; j++) {
		bs->putBit((mascara & nro) ? true : false);
		mascara >>= 1;
		//			salida += ((mascara & numero) ? "1" : "0");
	}
}


//ESTO ES RE CHANCHO PERO ES LO MAS RAPIDO QUE SE PUEDE HACER... HAY Q VER SI ANDA.
void escribirNumeroVariableLargo(BitStream* stream, PunteroPosiciones numero,
		EnteroLargo longitudBloque) {
	//Cuantos bits tiene el tipo.
	PunteroPosiciones bits = sizeof(EnteroLargo) * 8;
	PunteroPosiciones bit = 1;
	PunteroPosiciones mascara = bit << (bits - 1);
	int contador = 0;
	// cuento cuantos bits tiene la variable a escribir
	bool salir = false;
	while (mascara > 0 && salir == false) {
		contador++;
		salir = mascara & numero;
		mascara >>= 1;
	}
	int cantidadBitsAEscribir = bits + 1 - contador;
	//cantidad de bloques a escribir
	int cantBloquesEscribir = cantidadBitsAEscribir / longitudBloque;
	if (cantidadBitsAEscribir % longitudBloque > 0) {
		cantBloquesEscribir++;
	}
	//ahora empiezo a escribir;
	mascara = 1 << (cantBloquesEscribir * longitudBloque);
	//	string salida;
	//por cantidad de bytes.
	for (int i = 0; i < cantBloquesEscribir; i++) {
		//si hay mas bloques escribo un sigue.
		stream->putBit((cantBloquesEscribir > i + 1) ? true : false);
		//		salida += "|";
		//		salida += ((cantBloquesEscribir > i+1) ? "1" : "0");
		//escribo por bloques.
		for (EnteroLargo j = 0; j < longitudBloque; j++) {
			mascara >>= 1;
			stream->putBit((mascara & numero) ? true : false);
			//			salida += ((mascara & numero) ? "1" : "0");
		}
	}
	//		cout<< salida<< endl;
}

string to_string(EnteroLargo nro){
	std::ostringstream oss;
	oss<< nro;
	return oss.str();
}

FileList::FileList(const FileName & dir, const FileName & extension) {
	/* Variables */
	DIR *dirp;
	struct dirent *direntp;

	/* Comprobamos los argumentos */

	/* Abrimos el directorio */
	dirp = opendir(dir);
	if (dirp == NULL) {
		printf("Error: No se puede abrir el directorio\n");
	}

	string nombre;
	/* Leemos las entradas del directorio */
	EnteroLargo found;
	EnteroLargo found2;
	string ext = ".";
	ext += extension;
	while ((direntp = readdir(dirp)) != NULL) {
		nombre = direntp->d_name;
		found = nombre.rfind(ext);
		found2 = nombre.rfind("~");
		if (found != std::string::npos && found2 == std::string::npos) {
			nombre.insert(0, "/");
			nombre.insert(0, dir);
			this->archivos.push_back(nombre);
		}
	}
	closedir(dirp);
	this->it = this->archivos.begin();
}

bool FileList::hasNext() {
	return this->it != this->archivos.end();
}

FileName FileList::next() {
	string fn = *it;
	it++;
	return fn.c_str();
}
string convertInt(EnteroLargo number) {
	stringstream ss;//create a stringstream
	ss << number;//add number to the stream
	return ss.str();//return a string with the contents of the stream
}

void FileNameBuilder::append(EnteroLargo entero) {
	this->stream += convertInt(entero);
}

void FileNameBuilder::append(string cadena) {
	this->stream += cadena;
}

void FileNameBuilder::append(FileName filename) {
	this->stream += string(filename);
}

FileName FileNameBuilder::toFileName() {
	return stream.c_str();
}
